package cn.sunyblog.tool.threadpool;

import cn.sunyblog.tool.threadpool.config.DynamicThreadPoolConfig;
import cn.sunyblog.tool.threadpool.monitor.ThreadPoolMetrics;
import cn.sunyblog.tool.threadpool.queue.DynamicBlockingQueue;
import cn.sunyblog.tool.threadpool.strategy.DefaultAdjustmentStrategy;
import cn.sunyblog.tool.threadpool.strategy.AdjustmentStrategy;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;



/**
 * 动态线程池测试类
 * 
 * @author sunyblog
 */
public class DynamicThreadPoolTest {
    
    private DynamicThreadPoolExecutor executor;
    private DynamicThreadPoolConfig config;
    
    @BeforeEach
    public void setUp() {
        config = new DynamicThreadPoolConfig();
        config.setThreadPoolName("TestPool");
        config.setCorePoolSize(2);
        config.setMaximumPoolSize(5);
        config.setQueueCapacity(20);
        config.setMonitorInterval(5);
        config.setEnableAutoAdjustment(true);
        config.setEnableMetricsLogging(false); // 测试时关闭日志
        
        executor = new DynamicThreadPoolExecutor(config);
    }
    
    @AfterEach
    public void tearDown() {
        if (executor != null && !executor.isShutdown()) {
            executor.shutdown();
            try {
                if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
                    executor.shutdownNow();
                }
            } catch (InterruptedException e) {
                executor.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }
    
    @Test
    public void testBasicExecution() throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3);
        AtomicInteger counter = new AtomicInteger(0);
        
        for (int i = 0; i < 3; i++) {
            executor.execute(() -> {
                counter.incrementAndGet();
                latch.countDown();
            });
        }
        
        assertTrue(latch.await(5, TimeUnit.SECONDS));
        assertEquals(3, counter.get());
    }
    
    @Test
    public void testInitialConfiguration() {
        assertEquals(2, executor.getCorePoolSize());
        assertEquals(5, executor.getMaximumPoolSize());
        
        DynamicBlockingQueue<?> queue = (DynamicBlockingQueue<?>) executor.getQueue();
        assertEquals(20, queue.getCapacity());
    }
    
    @Test
    public void testMetricsCollection() throws InterruptedException {
        // 提交一些任务
        CountDownLatch latch = new CountDownLatch(5);
        for (int i = 0; i < 5; i++) {
            executor.execute(() -> {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    latch.countDown();
                }
            });
        }
        
        // 等待任务完成
        latch.await(5, TimeUnit.SECONDS);
        
        // 等待指标更新
        Thread.sleep(200);
        
        // 检查指标
        ThreadPoolMetrics metrics = executor.getCurrentMetrics();
        assertNotNull(metrics);
        assertTrue(metrics.getTotalSubmittedTasks() > 0);
        assertTrue(metrics.getTotalCompletedTasks() > 0);
    }
    
    @Test
    public void testQueueUsageRate() throws InterruptedException {
        DynamicBlockingQueue<?> queue = (DynamicBlockingQueue<?>) executor.getQueue();
        
        // 提交大量长时间任务，填满队列
        CountDownLatch startLatch = new CountDownLatch(1);
        CountDownLatch taskLatch = new CountDownLatch(15);
        
        for (int i = 0; i < 15; i++) {
            executor.execute(() -> {
                try {
                    startLatch.await(); // 等待开始信号
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    taskLatch.countDown();
                }
            });
        }
        
        // 等待队列填充
        Thread.sleep(100);
        
        // 检查队列使用率
        double usageRate = queue.getUsageRate();
        assertTrue(usageRate > 0);
        
        // 释放任务
        startLatch.countDown();
        taskLatch.await(5, TimeUnit.SECONDS);
    }
    
    @Test
    public void testDynamicQueueResize() {
        DynamicBlockingQueue<Runnable> queue = (DynamicBlockingQueue<Runnable>) executor.getQueue();
        
        assertEquals(20, queue.getCapacity());
        
        // 调整队列大小
        queue.setCapacity(30);
        assertEquals(30, queue.getCapacity());
        
        // 缩小队列
        queue.setCapacity(5);
        assertEquals(5, queue.getCapacity());
    }
    
    @Test
    public void testManualAdjustment() {
        int originalCoreSize = executor.getCorePoolSize();
        int originalMaxSize = executor.getMaximumPoolSize();
        
        // 由于是空闲状态，可能会缩容或保持不变
        // 这里主要测试线程池状态正常
        assertTrue(executor.getCorePoolSize() >= 1);
        assertTrue(executor.getMaximumPoolSize() >= executor.getCorePoolSize());
    }
    
    @Test
    public void testConfigValidation() {
        DynamicThreadPoolConfig testConfig = new DynamicThreadPoolConfig();
        
        // 测试正常配置
        testConfig.setCorePoolSize(5);
        testConfig.setMaximumPoolSize(10);
        testConfig.setQueueCapacity(20);
        testConfig.validate(); // 应该不抛出异常
        
        // 测试异常配置
        try {
            testConfig.setCorePoolSize(15); // 大于最大线程数
            testConfig.validate();
            fail("应该抛出异常");
        } catch (IllegalArgumentException e) {
            // 预期的异常
        }
    }
    
    @Test
    public void testAdjustmentStrategy() {
        DefaultAdjustmentStrategy strategy = new DefaultAdjustmentStrategy();
        
        assertNotNull("策略名称不应该为null", strategy.getStrategyName());
        assertNotNull("策略描述不应该为null", strategy.getDescription());
        
        // 创建一个高负载的指标
        ThreadPoolMetrics highLoadMetrics = new ThreadPoolMetrics(
            2, 5, 5, 5, 8, 10, 0.8, 0.9, 10.0, 5.0, 500.0, 1000, 100, 95, 0, 95, 5
        );
        
        // 测试是否会建议扩容
        AdjustmentStrategy.AdjustmentRecommendation recommendation = strategy.recommend(highLoadMetrics);
        if (recommendation != null) {
            assertTrue(recommendation.getNewCorePoolSize() >= highLoadMetrics.getCorePoolSize() ||
                recommendation.getNewMaximumPoolSize() >= highLoadMetrics.getMaximumPoolSize(),
                "高负载时应该建议增加线程数");
        }
    }
    
    @Test
    public void testThreadPoolShutdown() throws InterruptedException {
        assertTrue(!executor.isShutdown());
        
        executor.shutdown();
        assertTrue(executor.isShutdown());
        
        boolean terminated = executor.awaitTermination(5, TimeUnit.SECONDS);
        assertTrue(terminated);
    }
    
    @Test
    public void testConcurrentTaskExecution() throws InterruptedException {
        int taskCount = 20;
        CountDownLatch latch = new CountDownLatch(taskCount);
        AtomicInteger completedTasks = new AtomicInteger(0);
        
        for (int i = 0; i < taskCount; i++) {
            final int taskId = i;
            executor.execute(() -> {
                try {
                    Thread.sleep(50); // 短暂延迟
                    completedTasks.incrementAndGet();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    latch.countDown();
                }
            });
        }
        
        assertTrue(latch.await(10, TimeUnit.SECONDS));
        assertEquals(taskCount, completedTasks.get());
    }
}